package cConfig

import (
	"encoding/json"
	"errors"
	"sync"
	"time"

	"gitee.com/csingo/cComponents"
	"gitee.com/csingo/cHelper"
	"gitee.com/csingo/cLog"
)

func initClient(driver ConfigCenterDriver) (ClientInterface, error) {
	var client ClientInterface
	var err error

	switch driver {
	case FileDriver:
		client = &config_center_config.Clients.File
	case ZipDriver:
		client = &config_center_config.Clients.Zip
	case NacosDriver:
		client = &config_center_config.Clients.Nacos
	case CustomizeDriver:
		client = config_center_config.Clients.Customize
	default:
		return nil, errors.New("config_center_config.driver is not defined")
	}

	err = client.InitClient()
	if err != nil {
		return nil, err
	}

	return client, nil
}

func load() {
	cLog.WithContext(nil, map[string]any{
		"source": "cConfig.load",
	}, []cLog.Option{
		cLog.IncludePaths{},
	}).Trace("启动配置监听")

	// var client ClientInterface
	// var err error
	//
	// client, err = initClient(config_center_config.Driver)
	// if err != nil {
	// 	cLog.WithContext(nil, map[string]any{
	// 		"source": "cConfig.load",
	// 		"driver": config_center_config.Driver,
	// 		"err":    err.Error(),
	// 	}).Error("配置中心客户端初始化失败")
	// 	return
	// }

	// 首次加载
	for _, item := range config_center_config.Listens {
		catch(item)
	}

	// 持续监听
	timer := time.NewTicker(time.Duration(config_center_config.Interval) * time.Second)
	lock := &sync.Mutex{}
	go listen(timer, lock)
}

func listen(timer *time.Ticker, lock *sync.Mutex) {
	for {
		<-timer.C
		if !lock.TryLock() {
			continue
		}
		wg := &sync.WaitGroup{}
		wg.Add(len(config_center_config.Listens))
		for _, item := range config_center_config.Listens {
			go func(w *sync.WaitGroup, data ConfigCenterConf_ListenItem) {
				catch(data)
				w.Done()
			}(wg, item)
		}
		wg.Wait()
		lock.Unlock()
	}
}

func catch(item ConfigCenterConf_ListenItem) {
	// 阻塞panic
	defer cHelper.Recover()()

	var client ClientInterface
	var content string
	var err error

	var driver = config_center_config.Driver
	if item.Driver != "" {
		driver = item.Driver
	}

	client, err = initClient(driver)
	if err != nil {
		cLog.WithContext(nil, map[string]any{
			"source": "cConfig.catch",
			"driver": driver,
			"err":    err.Error(),
		}, []cLog.Option{
			cLog.IncludePaths{},
		}).Error("配置中心客户端初始化失败")
		return
	}

	// 读取配置内容
	instance := container.Get(item.Conf)
	content, err = client.ReadConf(item.Data, item.Group, true)
	if err != nil {
		cLog.WithContext(nil, map[string]any{
			"source": "cConfig.catch",
			"item":   item,
			"err":    err.Error(),
		}, []cLog.Option{
			cLog.IncludePaths{},
		}).Error("配置读取失败")
		return
	}

	// 版本比较
	newVersion := cHelper.Md5([]byte(content))
	if container.CompareVersion(item.Conf, newVersion) {
		return
	}

	// 解析配置
	if _, ok := instance.(cComponents.ConfigDecoderInterface); ok {
		err = instance.(cComponents.ConfigDecoderInterface).Decode(content)
		if err != nil {
			cLog.WithContext(nil, map[string]any{
				"source": "cConfig.catch",
				"item":   item,
				"err":    err.Error(),
			}, []cLog.Option{
				cLog.IncludePaths{},
			}).Error("配置 json 解析失败")
			return
		}
	} else {
		err = json.Unmarshal([]byte(content), instance)
		if err != nil {
			cLog.WithContext(nil, map[string]any{
				"source": "cConfig.catch",
				"item":   item,
				"err":    err.Error(),
			}, []cLog.Option{
				cLog.IncludePaths{},
			}).Error("配置 json 解析失败")
			return
		}
	}

	// 记录新版本
	container.SaveVersion(item.Conf, newVersion)

	// 通知更新
	listeners := container.GetConfigListeners(instance.(cComponents.ConfigInterface).ConfigName())
	for _, listener := range listeners {
		listener(instance.(cComponents.ConfigInterface))
	}
}
